using System;
using System.Collections.Generic;
using System.Text;
using System.Data;  
using System.ComponentModel;
using System.Collections;
using System.Reflection;
//// This namespace contains the business layer base classes,
//// InfoCollectionBase and InfoBase which can be used in
//// conjunction with a set of CodeSmith Templates to        


namespace PantheonSoftware.InfoCollection.Business
{
//// Item object
//// <summary>
//// This is the base class for the collection class.
//// 
//// Copyirght 2006-2007 Pantheon Software Management Ltd. All
//// Rights Reserved
//// 
//// Released under the GNU Lesser General Public License (LGPL).
//// See the license for full details. 
//// </summary>                                                  
    [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.InheritanceDemand, Name = "FullTrust")]
    [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name = "FullTrust")]
    public abstract class InfoCollectionBase<T> : IInfoCollection<T>, IDisposable
    {

        private DataSet _ds;
        private T[] _innerList = new T[0];

        private  ArrayList _sortedList = new ArrayList();
        private  ArrayList _originalList;
        private  bool _isSorted = false;
        private  PropertyDescriptor _sortBy;
        private  ListSortDirection _sortDirection = ListSortDirection.Descending;

        /// <summary>
        /// The explicit Reset event in the case that the collection has changed quite a lot
        /// </summary>
        protected ListChangedEventArgs resetEvent = new ListChangedEventArgs(ListChangedType.Reset, -1);

        //// <summary>
        //// The ListChanged event is fired every time the collection
        //// changes 
        //// </summary>                                              
        public event ListChangedEventHandler ListChanged;

        protected bool isDisposed;

        #region Constructors
        //// <summary>
        //// Initializes a new instance of the <see cref="PantheonSoftware.InfoCollection.Business.InfoBase" text="InfoCollectionBase\<T\>" />
        //// class. 
        //// </summary>                                                                                                                       
        public InfoCollectionBase()
        {
            isDisposed = false;
        }

        #endregion


        #region Business rules

        /// <summary>
        /// Fills this instance.
        /// This is the default holder for your main default business rule to fill the collection.
        /// Further Fill() methods with various parameters may be necessary.
        /// </summary>
        public abstract void Fill();

        //// <summary>
        //// Updates the underlying Dataset. Single Update, no transaction
        //// </summary>
        //// <returns>
        //// A DataSet with updated rows 
        //// </returns>                                                   
        public virtual DataSet Update()
        {
            return this.Update(null, UpdateType.SingleUpdate);
        }

        //// <summary>
        //// Starts the Update <see cref="Update" /> from the business
        //// layer.
        //// </summary>
        //// <param name="ut">The UpdateType can be SingleUpdate,
        ////                  RecursiveUpdate,
        ////                  SingleUpdateWithTransaction,
        ////                  RecursiveUpdateWithTransaction</param>
        //// <returns>
        //// A DataSet with updated rows
        //// </returns>                                               
        public virtual DataSet Update(UpdateType ut)
        {
            return Update(null, ut);
        }

        //// <summary>
        //// Persists the collection to the data source with or without
        //// transaction support
        //// </summary>
        //// <param name="dbManager">An object implementing IDbManager.</param>
        //// <param name="ut">The Update Type.</param>
        //// <returns>
        //// A DataSet with the update results
        //// 
        //// 
        //// </returns>
        //// __________________________________________________
        //// Note
        //// Because there is a need to update with a common transaction,
        //// the update is delegated to the DataManager object which will
        //// maintain its own connection and own transaction whilst
        //// calling (by delegation) several data object update methods.
        //// 
        //// 
        //// 
        //// As there can be several Update methods in a single Data
        //// Object, the update uses the UpdateDelegate to call the
        //// individual Update() methods, each time passing a reference if
        //// IDbManager, and hence the connection/transaction. In this way
        //// it is possible to persist the transaction across data
        //// \objects.
        //// 
        //// 
        //// 
        //// There is an example of an update statement in the
        //// InfoCollectionDerived Codesmith template.
        //// 
        //// 
        //// 
        //// It is recommended to adjust any default update to suit your
        //// own business rules and to take care when updating
        //// recursively though linked collections.
        ////                                                                   
        public abstract DataSet Update(IDbManager dbManager, UpdateType ut);

        /// <summary>
        /// Gets a value indicating whether the Collection has changes, including new, deleted, or modified items.
        /// </summary>
        public virtual bool HasChanges()
        {
            return _ds.HasChanges();
        }

        /// <summary>
        /// Gets a value indicating whether the Collection has changes, including new, deleted, or modified items.
        /// </summary>
        public virtual bool HasChanges(System.Data.DataRowState rowStates)
        {
            return _ds.HasChanges(rowStates);
        }

        /// <summary>
        /// Discard all changes made to the internal dataset.
        /// </summary>
        public abstract void Undo();

        ///<summary>
         ///Return a list of all records containing possible errors from last update.
         ///</summary>
         ///<returns>A list of records.</returns>
        public ArrayList GetUpdateErrors()
        {
            ArrayList al = new ArrayList();
            foreach (DataRow dr in this.Table.GetErrors())
	            al.Add(dr.RowError);
            return al;
        }

        //// <summary>
        //// Gets the first update error in a collection of row errors.
        //// </summary>
        //// <returns>
        //// \Returns the first row with an error
        //// </returns>                                                
        private string GetFirstUpdateError()
        {
            foreach (DataRow dr in this.Table.GetErrors())
                return dr.RowError;
            return "";
        }

        #endregion

        #region IList
        #region IList<T> Members

        /// <summary>
        /// Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1"></see>.
        /// </summary>
        /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.IList`1"></see>.</param>
        /// <returns>
        /// The index of item if found in the list; otherwise, -1.
        /// </returns>
        public virtual int IndexOf(T item)
        {
            for (int n = 0; n < this.Count; ++n)
            {
                if (this[n].Equals(item))
                    return n;
            }
            return -1;
        }

        /// <summary>
        /// Inserts an item to the <see cref="T:System.Collections.Generic.IList`1"></see> at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index at which item should be inserted.</param>
        /// <param name="item">The object to insert into the <see cref="T:System.Collections.Generic.IList`1"></see>.</param>
        /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1"></see> is read-only.</exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">index is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"></see>.</exception>
        public virtual void Insert(int index, T item)
        {
            //if (item.Parent == null)
            //    throw new ArgumentException("Cannot add object without a parent collection");
            if ((index < 0) || (index > this.Count))
                throw new ArgumentOutOfRangeException("index", index, "Index out of range");
            int count = _innerList.Length;
            if (count > 0)
            {
                T[] array = new T[count + 1];
                if (index > 0)
                    Array.Copy(_innerList, 0, array, 0, index);
                if (index < count)
                    Array.Copy(_innerList, index, array, index + 1, count - index);
                _innerList = array;
            }
            else
                _innerList = new T[1];
            _innerList[index] = item;
            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));
            return;
        }

        //// <summary>
        //// Removes the <see cref="T:System.Collections.IList" />item at
        //// the specified index.
        //// </summary>
        //// <param name="index">The zero\-based index of the item to
        ////                     remove.</param>
        //// <exception cref="T\:System.ArgumentOutOfRangeException">index
        ////                                                         is
        ////                                                         not
        ////                                                         a
        ////                                                         valid
        ////                                                         index
        ////                                                         in
        ////                                                         the <see cref="T:System.Collections.IList" />.
        ////                                                         </exception>
        //// <exception cref="T\:System.NotSupportedException">The <see cref="T:System.Collections.IList" />is
        ////                                                   read\-only.\-or\-
        ////                                                   The <see cref="T:System.Collections.IList" />has
        ////                                                   a
        ////                                                   fixed
        ////                                                   size.
        ////                                                   </exception>
        //// 
        //// <remarks>
        //// This method id abstract because of the object-specific code
        //// which needs t be implemented.
        //// 
        //// 
        //// 
        //// An example can be found in the CodeSmith template
        //// InfoCollectionDerived and in the example code
        //// (InfoCollectionTester).
        //// </remarks>                                                                                            
        public abstract void RemoveAt(int index);

        //// <summary>
        //// Gets or sets the item T at the specified index. 
        //// </summary>                                      
        public virtual T this[int index]
        {
            get { return _innerList[index]; }
            set
            {
                _innerList[index] = value;
                OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, index));
            }
        }

        #endregion

        #region IList Explicit Interface Methods

        /// <summary>
        /// Adds an item to the <see cref="T:System.Collections.IList"></see>.
        /// </summary>
        /// <param name="value">The <see cref="T:System.Object"></see> to add to the <see cref="T:System.Collections.IList"></see>.</param>
        /// <returns>
        /// The position into which the new element was inserted.
        /// </returns>
        /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.IList"></see> is read-only.-or- The <see cref="T:System.Collections.IList"></see> has a fixed size. </exception>
        int IList.Add(object value)
        {
            int cnt = this.Count;
            this.Add((T)value);
            return cnt;
        }

        /// <summary>
        /// Removes all PropertyInfo objects from the collection.
        /// </summary>
        bool IList.Contains(object value)
        {
            if (value == null)
                return false;

            return this.Contains((T)value);
        }

        /// <summary>
        /// Determines the index of a specific item in the <see cref="T:System.Collections.IList"></see>.
        /// </summary>
        /// <param name="value">The <see cref="T:System.Object"></see> to locate in the <see cref="T:System.Collections.IList"></see>.</param>
        /// <returns>
        /// The index of value if found in the list; otherwise, -1.
        /// </returns>
        int IList.IndexOf(object value)
        {
            if (value == null)
                return -1;

            return this.IndexOf((T)value);
        }

        /// <summary>
        /// Inserts an item to the <see cref="T:System.Collections.IList"></see> at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index at which value should be inserted.</param>
        /// <param name="value">The <see cref="T:System.Object"></see> to insert into the <see cref="T:System.Collections.IList"></see>.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">index is not a valid index in the <see cref="T:System.Collections.IList"></see>. </exception>
        /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.IList"></see> is read-only.-or- The <see cref="T:System.Collections.IList"></see> has a fixed size. </exception>
        /// <exception cref="T:System.NullReferenceException">value is null reference in the <see cref="T:System.Collections.IList"></see>.</exception>
        void IList.Insert(int index, object value)
        {
            this.Insert(index, (T)value);
        }

        //// <summary>
        //// Gets a value indicating whether the <see cref="T:System.Collections.IList" />has
        //// a fixed size.
        //// </summary>
        //// <returns>
        //// true if the <see cref="T:System.Collections.IList" />has a
        //// fixed size; otherwise, false.
        //// </returns>                                                                      
        bool IList.IsFixedSize
        {
            get { return false; }
        }

        //// <summary>
        //// Gets a value indicating whether the <see cref="T:System.Collections.IList" />is
        //// read-only.
        //// </summary>
        //// <returns>
        //// true if the <see cref="T:System.Collections.IList" />is
        //// read-only; otherwise, false.
        //// </returns>                                                                     
        bool IList.IsReadOnly
        {
            get { return false; }
        }

        /// <summary>
        /// Gets or sets the <see cref="System.Object"/> at the specified index.
        /// </summary>
        /// <value></value>
        object IList.this[int index]
        {
            get { return this[index]; }
            set { this[index] = (T)value; }
        }

        /// <summary>
        /// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.IList"></see>.
        /// </summary>
        /// <param name="value">The <see cref="T:System.Object"></see> to remove from the <see cref="T:System.Collections.IList"></see>.</param>
        /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.IList"></see> is read-only.-or- The <see cref="T:System.Collections.IList"></see> has a fixed size. </exception>
        void IList.Remove(object value)
        {
            this.Remove((T)value);
        }


        #endregion
        #endregion

        #region ICollection

        #region ICollection<T> Methods
        //// <summary>
        //// Adds an item to the <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_Generic_ICollection`1.htm">System.Collections.Generic.ICollection</exref>.
        //// </summary>
        //// <param name="item">The object to add to the <extlink ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_Generic_ICollection`1.htm>System.Collections.Generic.ICollection</extlink>.</param>
        //// <exception cref="System.NotSupportedException">The <extlink ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_Generic_ICollection`1.htm>System.Collections.Generic.ICollection</extlink>
        ////                                                is read\-only.</exception>                                                                                                                                        
        public virtual void Add(T item)
        {
            this.Insert(this.Count, item);
            this.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, this.Count));
        }

        //// <summary>
        //// Removes all items from the <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_IList.htm">System.Collections.IList</exref>.
        //// </summary>
        //// <exception cref="System.NotSupportedException">The <extlink ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_IList.htm>System.Collections.IList</extlink>
        ////                                                is read\-only.
        ////                                                </exception>                                                                                                                      
        public virtual void Clear()
        {
            _innerList = new T[0];
            this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, 0));
        }

        //// <summary>
        //// Determines whether the <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_Generic_ICollection`1.htm">System.Collections.Generic.ICollection</exref>contains
        //// a specific value.
        //// </summary>
        //// <param name="item">The object to locate in the <extlink ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_Generic_ICollection`1.htm>System.Collections.Generic.ICollection</extlink>.</param>
        //// <returns>
        //// true if item is found in the <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_Generic_ICollection`1.htm">System.Collections.Generic.ICollection</exref>;
        //// \otherwise, false. 
        //// </returns>                                                                                                                                                                                                          
        public virtual bool Contains(T item)
        {
            return this.IndexOf(item) >= 0;
        }

        //// <summary>
        //// Copies the elements of the <exref target="ms-help://MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_Generic_ICollection`1.htm">System.Collections.Generic.ICollection</exref>to
        //// an <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Array_Members.htm">System.Array</exref>,
        //// starting at a particular <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Array_Members.htm">System.Array</exref>
        //// index.
        //// </summary>
        //// <param name="array">The one\-dimensional <extlink ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Array_Members.htm>System.Array</extlink>that
        ////                     is the destination of the elements
        ////                     copied from <extlink ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_Generic_ICollection`1.htm>System.Collections.Generic.ICollection</extlink>.
        ////                     The <extlink ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Array_Members.htm>System.Array</extlink>
        ////                     must have zero\-based indexing.</param>
        //// <param name="arrayIndex">The zero\-based index in array at
        ////                          which copying begins.</param>
        //// <exception cref="T\:System.ArgumentOutOfRangeException">arrayIndex
        ////                                                         is
        ////                                                         less
        ////                                                         than
        ////                                                         0.</exception>
        //// <exception cref="T\:System.ArgumentNullException">array
        ////                                                   is
        ////                                                   null.</exception>
        //// <exception cref="T\:System.ArgumentException">array
        ////                                               is
        ////                                               multidimensional.\-or\-arrayIndex
        ////                                               is
        ////                                               equal
        ////                                               to
        ////                                               or
        ////                                               greater
        ////                                               than
        ////                                               the
        ////                                               length
        ////                                               of
        ////                                               array.\-or\-The
        ////                                               number
        ////                                               of
        ////                                               elements
        ////                                               in
        ////                                               the
        ////                                               source
        ////                                               <extlink ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_Generic_ICollection`1.htm>System.Collections.Generic.ICollection</extlink>is
        ////                                               greater
        ////                                               than
        ////                                               the
        ////                                               available
        ////                                               space
        ////                                               from
        ////                                               arrayIndex
        ////                                               to
        ////                                               the
        ////                                               end
        ////                                               of
        ////                                               the
        ////                                               destination
        ////                                               array.\-or\-Type
        ////                                               T
        ////                                               cannot
        ////                                               be
        ////                                               cast
        ////                                               automatically
        ////                                               to
        ////                                               the
        ////                                               type
        ////                                               of
        ////                                               the
        ////                                               destination
        ////                                               array.</exception>                                                                                                                                            
        public virtual void CopyTo(T[] array, int arrayIndex)
        {
            _innerList.CopyTo(array, arrayIndex);
        }

        //// <summary>
        //// Gets the number of elements contained in the <see cref="T:System.Collections.ICollection" />.
        //// </summary>
        //// <returns>
        //// The number of elements contained in the <see cref="T:System.Collections.ICollection" />.
        //// </returns>                                                                                   
        public virtual int Count
        {
            get { return _innerList.Length; }
        }

        //// <summary>
        //// Gets a value indicating whether the <see cref="T:System.Collections.IList" />is
        //// read-only.
        //// </summary>
        //// <returns>
        //// true if the <see cref="T:System.Collections.IList" />is
        //// read-only; otherwise, false.
        //// </returns>                                                                     
        public virtual bool IsReadOnly
        {
            get { return false; }
        }

        /// <summary>
        /// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"></see>.
        /// </summary>
        /// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"></see>.</param>
        /// <returns>
        /// true if item was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"></see>; otherwise, false. This method also returns false if item is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"></see>.
        /// </returns>
        /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"></see> is read-only.</exception>
        public virtual bool Remove(T item)
        {
            int inx = this.IndexOf(item);
            this.RemoveAt(inx);
            return true;
        }
        #endregion

        #region ICollection Explicit Interface Methods
        //// <summary>
        //// Gets a value indicating whether access to the <see cref="T:System.Collections.ICollection" />is
        //// synchronized (thread safe).
        //// </summary>
        //// <returns>
        //// true if access to the <see cref="T:System.Collections.ICollection" />is
        //// synchronized (thread safe); otherwise, false.
        //// </returns>                                                                                     
        bool ICollection.IsSynchronized
        {
            get { return false; }
        }

        //// <summary>
        //// Gets an object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection" />.
        //// </summary>
        //// <returns>
        //// An object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection" />.
        //// </returns>                                                                                                   
        object ICollection.SyncRoot
        {
            get { return _innerList.SyncRoot; }
        }

        //// <docsource type="copy" target="PantheonSoftware.InfoCollection.Business.InfoCollectionBase.CopyTo@T[]@int" />
        //// 
        //// <summary>
        //// Copies the elements of the <see cref="T:System.Collections.ICollection" />to
        //// an <see cref="T:System.Array" />, starting at a particular <see cref="T:System.Array" />index.
        //// </summary>
        //// <param name="array">The one\-dimensional <see cref="T:System.Array" />that
        ////                     is the destination of the elements
        ////                     copied from <see cref="T:System.Collections.ICollection" />.
        ////                     The <see cref="T:System.Array" />must
        ////                     have zero\-based indexing.</param>
        //// <param name="index">The zero\-based index in array at which
        ////                     copying begins.</param>
        //// <exception cref="T\:System.ArgumentNullException">array
        ////                                                   is
        ////                                                   null.
        ////                                                   </exception>
        //// <exception cref="T\:System.ArgumentOutOfRangeException">index
        ////                                                         is
        ////                                                         less
        ////                                                         than
        ////                                                         zero.
        ////                                                         </exception>
        //// <exception cref="T\:System.ArgumentException">array
        ////                                               is
        ////                                               multidimensional.\-or\-
        ////                                               index
        ////                                               is
        ////                                               equal
        ////                                               to
        ////                                               or
        ////                                               greater
        ////                                               than
        ////                                               the
        ////                                               length
        ////                                               of
        ////                                               array.\-or\-
        ////                                               The
        ////                                               number
        ////                                               of
        ////                                               elements
        ////                                               in
        ////                                               the
        ////                                               source
        ////                                               <see cref="T:System.Collections.ICollection" />is
        ////                                               greater
        ////                                               than
        ////                                               the
        ////                                               available
        ////                                               space
        ////                                               from
        ////                                               index
        ////                                               to
        ////                                               the
        ////                                               end
        ////                                               of
        ////                                               the
        ////                                               destination
        ////                                               array.
        ////                                               </exception>
        //// <exception cref="T\:System.InvalidCastException">The
        ////                                                  type
        ////                                                  of
        ////                                                  the
        ////                                                  source
        ////                                                  <see cref="T:System.Collections.ICollection" />cannot
        ////                                                  be
        ////                                                  cast
        ////                                                  automatically
        ////                                                  to
        ////                                                  the
        ////                                                  type
        ////                                                  of
        ////                                                  the
        ////                                                  destination
        ////                                                  array.
        ////                                                  </exception>                                                
        void ICollection.CopyTo(System.Array array, int index)
        {
            _innerList.CopyTo(array, index);
        }
        #endregion
        
        #endregion

        #region IEnumerable<T> Members

        //// <summary>
        //// \Returns an enumerator that iterates through the collection.
        //// </summary>
        //// <returns>
        //// A <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_IEnumerator.htm">System.Collections.Generic.IEnumerator</exref>
        //// that can be used to iterate through the collection. 
        //// </returns>                                                                                                                                               
        public virtual IEnumerator<T> GetEnumerator()
        {
            return (IEnumerator<T>)new InfoCollectionEnumerator<T>(this.InnerList);
        }

        #endregion

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.
        /// </returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion

        #region IBindingList Members

        /// <summary>
        /// Raises the <see cref="E:ListChanged"/> event.
        /// </summary>
        /// <param name="eventArgs">The <see cref="System.ComponentModel.ListChangedEventArgs"/> instance containing the event data.</param>
        protected void OnListChanged(ListChangedEventArgs eventArgs)
        {
            if (ListChanged != null)
                ListChanged(this, eventArgs);
        }


        //// <summary>
        //// The private IBindingList implementation which calls the <see cref="PantheonSoftware.InfoCollection.Business.InfoCollectionBase.ListChanged" text="ListChanged" />
        //// event.
        //// </summary>                                                                                                                                                       
        event ListChangedEventHandler IBindingList.ListChanged
        {
            add
            {
                ListChanged += value;
            }
            remove
            {
                ListChanged -= value;
            }
        }

        /// <summary>
        /// Not Implemented
        /// </summary>
        void IBindingList.AddIndex(PropertyDescriptor property)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        /// <summary>
        /// Not Implemented
        /// </summary>
        void IBindingList.RemoveIndex(PropertyDescriptor property)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        /// <summary>
        /// Adds a new item to the list.
        /// </summary>
        /// <returns>The item added to the list.</returns>
        /// <exception cref="T:System.NotSupportedException"><see cref="P:System.ComponentModel.IBindingList.AllowNew"></see> is false. </exception>
        object IBindingList.AddNew()
        {
            return this.AddNew();
        }

        //// <summary>
        //// Gets whether you can update items in the list.
        //// </summary>
        //// <returns>
        //// true if you can update the items in the list; otherwise,
        //// false.
        //// </returns>                                              
        public virtual bool AllowEdit
        {
            get { return true; }
        }

        //// <summary>
        //// Gets whether you can add items to the list using <see cref="M:System.ComponentModel.IBindingList.AddNew" />.
        //// </summary>
        //// <returns>
        //// true if you can add items to the list using <see cref="M:System.ComponentModel.IBindingList.AddNew" />;
        //// \otherwise, false.
        //// </returns>                                                                                                  
        public virtual bool AllowNew
        {
            get { return true; }
        }

        //// <summary>
        //// Gets whether you can remove items from the list, using <see cref="M:System.Collections.IList.Remove(System.Object)" />or
        //// <see cref="M:System.Collections.IList.RemoveAt(System.Int32)" />.
        //// </summary>
        //// <returns>
        //// true if you can remove items from the list; otherwise, false.
        //// </returns>                                                                                                              
        public virtual bool AllowRemove
        {
            get { return true; }
        }

        /// <summary>
        /// Sorts the collection
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="direction">The direction.</param>
        public virtual void ApplySort(System.ComponentModel.PropertyDescriptor propertyName, System.ComponentModel.ListSortDirection direction)
        {
            _sortBy = propertyName;
            _sortDirection = direction;
            SortList();
        }

        /// <summary>
        /// Sorts the collection
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="direction">The  direction.</param>
        public virtual void ApplySort(string propertyName, System.ComponentModel.ListSortDirection direction)
        {
            this.ApplySort(UtilityClass.PropertyFromFieldName(typeof(T), propertyName), direction);
        }

        /// <summary>
        /// Finds the specified property name.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        int IBindingList.Find(System.ComponentModel.PropertyDescriptor propertyName, object key)
        {
            return Find(propertyName, (T)key);
        }

        //// <summary>
        //// \Returns the index of the row that has the given <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref3/html/T_System_ComponentModel_PropertyDescriptor.htm">PropertyDescriptor</exref>.
        //// </summary>
        //// <param name="propertyName">Name of the property.</param>
        //// <param name="key">Key to be used in search.</param>
        //// <returns>
        //// \ \ 
        //// </returns>                                                                                                                                                                                     
        public virtual int Find(System.ComponentModel.PropertyDescriptor propertyName, T key)
        {
            
            foreach (T fi in this)
            {
                if (key.Equals((T)propertyName.GetValue(fi)))
                    return this.IndexOf(fi);
            }
            return -1;
        }

        //// <summary>
        //// \Returns the index of the row that has the given Property.
        //// </summary>
        //// <param name="propertyName">Text name of the property.</param>
        //// <param name="key">Key to be used in search.</param>
        //// <returns>
        //// \ \ 
        //// </returns>                                                   
        public virtual int Find(string propertyName, T key)
        {
            PropertyDescriptor pd = UtilityClass.PropertyFromFieldName(typeof(T), propertyName);
            return this.Find(pd, key);
        }

        //// <summary>
        //// Gets whether the items in the list are sorted.
        //// </summary>
        //// <returns>
        //// true if <see cref="M:System.ComponentModel.IBindingList.ApplySort(System.ComponentModel.PropertyDescriptor,System.ComponentModel.ListSortDirection)" />has
        //// been called and <see cref="M:System.ComponentModel.IBindingList.RemoveSort" />has
        //// not been called; otherwise, false.
        //// </returns>
        //// <exception cref="T\:System.NotSupportedException"><see cref="P:System.ComponentModel.IBindingList.SupportsSorting" />is
        ////                                                   false. </exception>                                                                                     
        public virtual bool IsSorted
        {
            get { return _isSorted; }
        }

        /// <summary>
        /// Removes any sort applied using <see cref="M:System.ComponentModel.IBindingList.ApplySort(System.ComponentModel.PropertyDescriptor,System.ComponentModel.ListSortDirection)"></see>.
        /// </summary>
        /// <exception cref="T:System.NotSupportedException"><see cref="P:System.ComponentModel.IBindingList.SupportsSorting"></see> is false. </exception>
        public virtual void RemoveSort()
        {
            if (_isSorted)
            {
                this.Clear();
                foreach (T obj in _originalList)
                    this.Add(obj);
                _isSorted = false;
                _originalList = null; //destroy
                OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, 0));
            }
        }

        //// <summary>
        //// Gets the direction of the sort.
        //// </summary>
        //// <returns>
        //// One of the <see cref="T:System.ComponentModel.ListSortDirection" />values.
        //// </returns>
        //// <exception cref="T\:System.NotSupportedException"><see cref="P:System.ComponentModel.IBindingList.SupportsSorting" />is
        ////                                                   false. </exception>                                                  
        public virtual ListSortDirection SortDirection
        {
            get { return _sortDirection; }
        }

        //// <summary>
        //// Gets the PropertyDescriptor that is being used for sorting.
        //// </summary>
        //// <returns>
        //// The <exref target="System.ComponentModel.PropertyDescriptor">System.ComponentModel.PropertyDescriptor</exref>that
        //// is being used for sorting.
        //// </returns>
        //// <exception cref="T\:System.NotSupportedException"><see cref="P:System.ComponentModel.IBindingList.SupportsSorting" />is
        ////                                                   false. </exception>                                                  
        public System.ComponentModel.PropertyDescriptor SortProperty
        {
            get { return _sortBy; }
        }

        //// <summary>
        //// Gets whether a <see cref="ListChanged" /> event is raised
        //// when the list changes or an item in the list changes. Returns
        //// <b>true</b>.
        //// </summary>
        //// <returns>
        //// true if a <see cref="E:System.ComponentModel.IBindingList.ListChanged" />event
        //// is raised when the list changes or when an item changes;
        //// \otherwise, false.
        //// </returns>                                                                    
        public bool SupportsChangeNotification
        {
            get { return true; }
        }

        //// <summary>
        //// Gets whether the list supports searching using the <see cref="Find" />
        //// method. Returns <b>true</b>.
        //// </summary>
        //// <returns>
        //// true if the list supports searching using the <see cref="M:System.ComponentModel.IBindingList.Find(System.ComponentModel.PropertyDescriptor,System.Object)" />method;
        //// \otherwise, false.
        //// </returns>                                                                                                                                                           
        public bool SupportsSearching
        {
            get { return true; }
        }

        //// <summary>
        //// Gets whether the list supports sorting. Returns <b>true</b>.
        //// </summary>
        //// <returns>
        //// true if the list supports sorting; otherwise, false.
        //// </returns>                                                  
        public bool SupportsSorting
        {
            get { return true; }
        }

        
        #endregion

        #region Abstract Methods

        
        //// <summary>
        //// Adds a new item to the collection.
        //// </summary>
        //// <example>
        //// <c> public override CustomerInfo AddNew()</c>
        //// 
        //// <c> {</c>
        //// 
        //// <c> //'TODO: Add Business Logic for adding new item here</c>
        //// 
        //// <c> if (this.DataSet == null)</c>
        //// 
        //// <c> {</c>
        //// 
        //// <c> DCustomers dlc = new DCustomers();</c>
        //// 
        //// <c> this.DataSet = dlc.InnerDS;</c>
        //// 
        //// <c> }</c>
        //// 
        //// <c> DataRow dr = this.Table.NewRow();</c>
        //// 
        //// <c> CustomerInfo fi = new CustomerInfo(this, dr);</c>
        //// 
        //// <c> this.Add(fi);</c>
        //// 
        //// <c> //'TODO: Set Primary Key here</c>
        //// 
        //// 
        //// 
        //// <c> //'Add row to data table</c>
        //// 
        //// 
        //// 
        //// <c> this.Table.Rows.Add(dr);</c>
        //// 
        //// <c> return fi;</c>
        //// 
        //// <c> }</c>
        //// </example>
        //// <returns>
        //// The type-safe object
        //// </returns>                                                  
        public abstract T AddNew();
        
        #endregion  

        #region Collection Properties
        /// <summary>
        /// Gets the underlying table.
        /// </summary>
        /// <value>The table.</value>
        public abstract DataTable Table
        {
            get; //{ return _ds.Tables["Property"]; }
        }

        /// <summary>
        /// Gets or sets the data set.
        /// </summary>
        /// <value>The data set.</value>
        public DataSet DataSet
        {
            get { return _ds; }
            set { _ds = value; }
        }

        /// <summary>
        /// Gets or sets the inner list.
        /// </summary>
        /// <value>The inner list.</value>
        protected T[] InnerList
        {
            get { return _innerList;  }
            set { _innerList = value; }
        }

        /// <summary>
        /// Not Sure about this one. May need a read/write property
        /// </summary>
        /// <value>The sorted list.</value>
        protected ArrayList SortedList
        {
            get { return _sortedList; }
        }

        /// <summary>
        /// Gets or sets the original list.
        /// </summary>
        /// <value>The original list.</value>
        protected ArrayList OriginalList
        {
            get { return _originalList; }
            set { _originalList = value; }
        }

        /// <summary>
        /// Property which allows pre-seting of the sort property. By default this is "".
        /// </summary>
        /// <value>The sort by.</value>
        public virtual string SortBy
        {
            get 
            {
                if (null == _sortBy)
                    return string.Empty;
                else
                    return _sortBy.Name; 
            }

            set 
            { 
                _sortBy = UtilityClass.PropertyFromFieldName(typeof(T), value);  
            }
        }
        
        #endregion

        #region IDisposable Members
        /// <summary>
        /// Implements collection disposal via the Clear() method.
        /// </summary>
        public virtual void Dispose()
        {
            isDisposed = true;
            this.Clear();
            _ds.Dispose();
        }

        #endregion

        #region Sort

        /// <summary>
        /// Sorts the elements in the Collection .
        /// </summary>
        private void SortList()
        {
            _sortedList.Clear();
            //Load List to sort.
            _sortedList.AddRange(_innerList);
            //if not already sorted, create a backup of original
            if (!_isSorted)
                _originalList = new ArrayList(_innerList);
            //Sort List
            _sortedList.Sort();
            //Clear real list.
            this.Clear();
            //re-add item in sorted order.
            if (_sortDirection == ListSortDirection.Ascending)
            {
                for (int x = 0; x < _sortedList.Count; x++)
                {
                    this.Add(((T)_sortedList[x]));
                }
            }
            else
            {
                for (int x = _sortedList.Count - 1; x != -1; x--)
                {
                    this.Add(((T)_sortedList[x]));
                }
            }
            _isSorted = true;

            OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, 0));
        }


        /// <summary>
        ///		Sorts the collection based upon field selected.
        /// </summary>
        /// <param name="field">Field of the object on which to sort.</param>
        /// <param name="direction">Direction to sort in, Ascending or Descending.</param>

        public virtual void Sort(ListSortDirection direction, System.Reflection.PropertyInfo field)
        {
            _sortBy = UtilityClass.PropertyFromFieldName(typeof(T), field.ToString());
            _sortDirection = direction;
            this.SortList();
        }

        /// <summary>
        ///		Sorts the collection based on primary key.
        /// </summary>
        /// <param name="direction">Direction to sort in, Ascending or Descending.</param>
        public virtual void Sort(ListSortDirection direction)
        {
            _sortBy = null;
            _sortDirection = direction;
            this.SortList();
        }

        /// <summary>
        ///		Sorts the collection based on primary key. Sorts in Ascending order.
        /// </summary>
        public virtual void Sort()
        {
            _sortBy = null;
            _sortDirection = ListSortDirection.Ascending;
            this.SortList();
        }

        #endregion Sort
    }

    #region Enumerator

    /// <summary>
    /// Custom Enumerator which enumerates items from 0 to count-1
    /// </summary>
    /// <param name="T">The type of the collection item</param>
    public class InfoCollectionEnumerator<T> : IEnumerator<T>
    {
        private T[] _array;
        private int _nPos = -1;

        //// <summary>
        //// Initializes a new instance of the InfoCollectionEnumerator
        //// class.
        //// </summary>
        //// <param name="array">The array.</param>                    
        public InfoCollectionEnumerator(T[] array)
        {
            _array = array;
        }

        #region IEnumerator<T> Members

        /// <summary>
        /// Gets the element in the collection at the current position of the enumerator.
        /// </summary>
        /// <value></value>
        /// <returns>The element in the collection at the current position of the enumerator.</returns>
        public T Current
        {
            get { return _array[_nPos]; }
        }

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            _array = null;
        }

        #endregion

        #region IEnumerator Members

        /// <summary>
        /// Gets the element in the collection at the current position of the enumerator.
        /// </summary>
        /// <value></value>
        /// <returns>The element in the collection at the current position of the enumerator.</returns>
        object IEnumerator.Current
        {
            get { return this.Current; }
        }

        /// <summary>
        /// Advances the enumerator to the next element of the collection.
        /// </summary>
        /// <returns>
        /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
        /// </returns>
        /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception>
        public bool MoveNext()
        {
            _nPos++;
            return (_nPos < _array.GetLength(0));
        }

        /// <summary>
        /// Sets the enumerator to its initial position, which is before the first element in the collection.
        /// </summary>
        /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception>
       public void Reset()
        {
            _nPos = -1;
        }
        #endregion
    }
    #endregion
}
